Data import and Data cleaning

This section includes the code for downloading the data & various data cleansing steps:

library(tidyverse)
library(DataExplorer)
library(DT)

# Read dataset
original_span <- read_csv("https://sg-exercise.s3-eu-west-1.amazonaws.com/assignment_rev2.csv")

# Data cleaning
span <-
  original_span %>%
  distinct(across(c(-id, -agent_id, -ranking_score)), .keep_all = TRUE) %>% # Select unique records
  mutate(year_of_construction = na_if(year_of_construction, 2155)) %>% # Convert 2155 to missing value
  filter(price >= 7000) # Filter price based on the minimum house price... 8000 on various Greek websites

Assignment Part 1

It includes the r code and the table of summarized results.


span %>%
  group_by(subtype, geography_name) %>%
  summarise(N = n(), mean_price = round(mean(price), 0), median_price = round(median(price), 0), sd_price = round(sd(price), 0)) %>% 
  datatable(filter = 'top') %>% 
  formatCurrency(c('mean_price', 'median_price', 'sd_price'), currency = "€", digits = 0)
`summarise()` regrouping output by 'subtype' (override with `.groups` argument)

Assignment Part 3

Since the target is to develop a machine learning model we have to take a good look on which features we should use. The following plot shows the proportion of missing values per variable

We should definitely exclude equipped variable since all values are missing. Also, the id & agent_id were excluded beacause these are not useful in a model. Furthermore since there are a lot of variables with missing values, i decided to exclude all these variables. In a next step (with more available time) these variables could be included with the appropriate treatment e.g. imputation, encoding.

# Create the dataset for the modelling phase
span_model <- 
  span %>% 
  select(-equipped, -id, -agent_id) %>% 
  filter(is.na(year_of_construction) == FALSE & year_of_construction > 1900) %>% 
  select(ranking_score, geography_name, sq_meters, price, year_of_construction,
       subtype, rooms, no_of_bathrooms, no_of_wc, ad_type, living_rooms, 
       kitchens, balcony_area) 
  

Assignment Part 2

A very important metric to show the competitiveness is the price. The following table lists some basic price measures per area

span %>% 
  group_by(geography_name) %>% 
  summarise(N = n(),
            mean_price = round(mean(price), 0), 
            sd_price = round(sd(price), 0),
            min_price = min(price),
            quantile_25 = quantile(price, probs = .25),
            median = median(price),
            quantile = quantile(price, probs = .75),
            max_price = max(price)
            ) %>%
  datatable()
`summarise()` ungrouping output (override with `.groups` argument)
library(plotly)
library(ggthemes)
library(scales)


ggplotly(
         ggplot(span, aes(price, fill = geography_name)) +
         geom_density(alpha = 0.5) +
         scale_x_log10(labels = dollar_format(suffix = "€", prefix = "")) +
         theme_fivethirtyeight() +
         scale_fill_tableau() +
         theme(legend.title = element_blank()) +
         labs(title = "Property prices distribution per area")
          )
plotly.js does not (yet) support horizontal legend items 
You can track progress here: 
https://github.com/plotly/plotly.js/issues/53 

Some next steps would be to discover other measures and check how different these are per area. At the end it will be a good idea to develop a single KPI to measure the competitiveness of each area. This KPI would combine all significant measures we have discovered. This would definitely need close cooperation with business stakeholders and house market experts.

LS0tCnRpdGxlOiAiICIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBEYXRhIGltcG9ydCBhbmQgRGF0YSBjbGVhbmluZwoKVGhpcyBzZWN0aW9uIGluY2x1ZGVzIHRoZSBjb2RlIGZvciBkb3dubG9hZGluZyB0aGUgZGF0YSAmIHZhcmlvdXMgZGF0YSAKY2xlYW5zaW5nIHN0ZXBzOiAKCi0gUGVyZm9ybWVkIGRhdGEgZGUtZHVwbGljYXRpb24gYXMgdGhlcmUgd2VyZSBtYW55IGR1cGxpY2F0ZSByZWNvcmRzIAotIEZpbHRlciBvdXQgYWxsIGhvdXNlcyB3aXRoIHByaWNlIGxlc3MgdGhhbiDigqwgNy4wMDAgYXMgdGhlc2UgYXJlIHByb2JhYmx5IHR5cGluZyAKbWlzdGFrZXMgKGJhc2VkIG9uIHZhcmlvdXMgcmVhbCBlc3RhdGUgc2l0ZSkKCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoRGF0YUV4cGxvcmVyKQpsaWJyYXJ5KERUKQoKIyBSZWFkIGRhdGFzZXQKb3JpZ2luYWxfc3BhbiA8LSByZWFkX2NzdigiaHR0cHM6Ly9zZy1leGVyY2lzZS5zMy1ldS13ZXN0LTEuYW1hem9uYXdzLmNvbS9hc3NpZ25tZW50X3JldjIuY3N2IikKCiMgRGF0YSBjbGVhbmluZwpzcGFuIDwtCiAgb3JpZ2luYWxfc3BhbiAlPiUKICBkaXN0aW5jdChhY3Jvc3MoYygtaWQsIC1hZ2VudF9pZCwgLXJhbmtpbmdfc2NvcmUpKSwgLmtlZXBfYWxsID0gVFJVRSkgJT4lICMgU2VsZWN0IHVuaXF1ZSByZWNvcmRzCiAgbXV0YXRlKHllYXJfb2ZfY29uc3RydWN0aW9uID0gbmFfaWYoeWVhcl9vZl9jb25zdHJ1Y3Rpb24sIDIxNTUpKSAlPiUgIyBDb252ZXJ0IDIxNTUgdG8gbWlzc2luZyB2YWx1ZQogIGZpbHRlcihwcmljZSA+PSA3MDAwKSAjIEZpbHRlciBwcmljZSBiYXNlZCBvbiB0aGUgbWluaW11bSBob3VzZSBwcmljZS4uLiA4MDAwIG9uIHZhcmlvdXMgR3JlZWsgd2Vic2l0ZXMKCmBgYAoKCgojIEFzc2lnbm1lbnQgUGFydCAxCgpJdCBpbmNsdWRlcyB0aGUgciBjb2RlIGFuZCB0aGUgdGFibGUgb2Ygc3VtbWFyaXplZCByZXN1bHRzLiAKCmBgYHtyfQoKc3BhbiAlPiUKICBncm91cF9ieShzdWJ0eXBlLCBnZW9ncmFwaHlfbmFtZSkgJT4lCiAgc3VtbWFyaXNlKE4gPSBuKCksIG1lYW5fcHJpY2UgPSByb3VuZChtZWFuKHByaWNlKSwgMCksIG1lZGlhbl9wcmljZSA9IHJvdW5kKG1lZGlhbihwcmljZSksIDApLCBzZF9wcmljZSA9IHJvdW5kKHNkKHByaWNlKSwgMCkpICU+JSAKICBkYXRhdGFibGUoZmlsdGVyID0gJ3RvcCcpICU+JSAKICBmb3JtYXRDdXJyZW5jeShjKCdtZWFuX3ByaWNlJywgJ21lZGlhbl9wcmljZScsICdzZF9wcmljZScpLCBjdXJyZW5jeSA9ICLigqwiLCBkaWdpdHMgPSAwKQoKYGBgCgojIEFzc2lnbm1lbnQgUGFydCAzIAoKU2luY2UgdGhlIHRhcmdldCBpcyB0byBkZXZlbG9wIGEgbWFjaGluZSBsZWFybmluZyBtb2RlbCB3ZSBoYXZlIHRvIHRha2UgYSBnb29kIGxvb2sgCm9uIHdoaWNoIGZlYXR1cmVzIHdlIHNob3VsZCB1c2UuIFRoZSBmb2xsb3dpbmcgcGxvdCBzaG93cyB0aGUgcHJvcG9ydGlvbiBvZiBtaXNzaW5nCnZhbHVlcyBwZXIgdmFyaWFibGUKCgpgYGB7ciBmaWcud2lkdGg9MTB9CgpwbG90X21pc3Npbmcoc3BhbiwgbWlzc2luZ19vbmx5ID0gVFJVRSwgdGl0bGUgPSAiTWlzc2luZyB2YWx1ZXMgJSBwZXIgdmFyaWFibGUiKQoKYGBgCgoKV2Ugc2hvdWxkIGRlZmluaXRlbHkgZXhjbHVkZSAqKmVxdWlwcGVkKiogdmFyaWFibGUgc2luY2UgYWxsIHZhbHVlcyBhcmUgbWlzc2luZy4gQWxzbywKdGhlICoqaWQqKiAmICoqYWdlbnRfaWQqKiB3ZXJlIGV4Y2x1ZGVkIGJlYWNhdXNlIHRoZXNlIGFyZSBub3QgdXNlZnVsIGluIGEgbW9kZWwuIApGdXJ0aGVybW9yZSBzaW5jZSB0aGVyZSBhcmUgYSBsb3Qgb2YgdmFyaWFibGVzIHdpdGggbWlzc2luZyB2YWx1ZXMsIGkgZGVjaWRlZCB0bwoqKmV4Y2x1ZGUgYWxsIHRoZXNlIHZhcmlhYmxlcyoqLiBJbiBhIG5leHQgc3RlcCAod2l0aCBtb3JlIGF2YWlsYWJsZSB0aW1lKSB0aGVzZSAKdmFyaWFibGVzIGNvdWxkIGJlIGluY2x1ZGVkIHdpdGggdGhlIGFwcHJvcHJpYXRlIHRyZWF0bWVudCBlLmcuIGltcHV0YXRpb24sIGVuY29kaW5nLiAgCgpgYGB7cn0KIyBDcmVhdGUgdGhlIGRhdGFzZXQgZm9yIHRoZSBtb2RlbGxpbmcgcGhhc2UKc3Bhbl9tb2RlbCA8LSAKICBzcGFuICU+JSAKICBzZWxlY3QoLWVxdWlwcGVkLCAtaWQsIC1hZ2VudF9pZCkgJT4lIAogIGZpbHRlcihpcy5uYSh5ZWFyX29mX2NvbnN0cnVjdGlvbikgPT0gRkFMU0UgJiB5ZWFyX29mX2NvbnN0cnVjdGlvbiA+IDE5MDApICU+JSAKICBzZWxlY3QocmFua2luZ19zY29yZSwgZ2VvZ3JhcGh5X25hbWUsIHNxX21ldGVycywgcHJpY2UsIHllYXJfb2ZfY29uc3RydWN0aW9uLAogICAgICAgc3VidHlwZSwgcm9vbXMsIG5vX29mX2JhdGhyb29tcywgbm9fb2Zfd2MsIGFkX3R5cGUsIGxpdmluZ19yb29tcywgCiAgICAgICBraXRjaGVucywgYmFsY29ueV9hcmVhKSAKICAKCmBgYAoKCiMgX0RldmVsb3AgYSBHQk0gd2l0aCBncmlkIHNlYXJjaAoKSSB1c2VkIHRoZSBnYm0gcGFja2FnZSB0byBkZXZlbG9wIGEgZ3JhZGllbnQgYm9vc3RpbmcgbWFjaGluZSBtb2RlbC4gQnV0IGluc3RlYWQgb2YgCm1hbnVhbGx5IHR3ZWFraW5nIGh5cGVycGFyYW1ldGVycyBvbmUgYXQgYSB0aW1lLCBpIGNyZWF0ZWQgYSBncmlkIHNlYXJjaCB3aGljaCAKaXRlcmF0ZXMgb3ZlciBldmVyeSBjb21iaW5hdGlvbiBvZiBoeXBlcnBhcmFtZXRlciB2YWx1ZXMgYW5kIGRldmVsb3BzIG11bHRpcGxlIAptb2RlbHMgKDgxIGluIG91ciBjYXNlKSBzbyBpIGNhbiBjaG9vc2UgdGhlIGJlc3Qgb25lLgoKCmBgYHtyfQoKbGlicmFyeShnYm0pCgpzcGFuX21vZGVsIDwtIAogIGFzLmRhdGEuZnJhbWUodW5jbGFzcyhzcGFuX21vZGVsKSwgc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUUpCgoKIyBjcmVhdGUgaHlwZXJwYXJhbWV0ZXIgZ3JpZApoeXBlcl9ncmlkIDwtIGV4cGFuZC5ncmlkKAogIHNocmlua2FnZSA9IGMoLjAxLCAuMDUsIC4xKSwKICBpbnRlcmFjdGlvbi5kZXB0aCA9IGMoMywgNSwgNyksCiAgbi5taW5vYnNpbm5vZGUgPSBjKDUsIDcsIDEwKSwKICBiYWcuZnJhY3Rpb24gPSBjKC42NSwgLjgsIDEpLCAKICBvcHRpbWFsX3RyZWVzID0gMCwgICAgICAgICAgICAgICAjIGEgcGxhY2UgdG8gZHVtcCByZXN1bHRzCiAgbWluX1JNU0UgPSAwICAgICAgICAgICAgICAgICAgICAgIyBhIHBsYWNlIHRvIGR1bXAgcmVzdWx0cwopCgoKIyByYW5kb21pemUgZGF0YQpyYW5kb21faW5kZXggPC0gc2FtcGxlKDE6bnJvdyhzcGFuX21vZGVsKSwgbnJvdyhzcGFuX21vZGVsKSkKcmFuZG9tX3NwYW5fbW9kZWwgPC0gc3Bhbl9tb2RlbFtyYW5kb21faW5kZXgsIF0KCgojIGdyaWQgc2VhcmNoIApmb3IoaSBpbiAxOm5yb3coaHlwZXJfZ3JpZCkpIHsKICAKICAjIHJlcHJvZHVjaWJpbGl0eQogIHNldC5zZWVkKDEyMykKICAKICAjIHRyYWluIG1vZGVsCiAgZ2JtLnR1bmUgPC0gZ2JtKAogICAgZm9ybXVsYSA9IHByaWNlIH4gLiwKICAgIGRpc3RyaWJ1dGlvbiA9ICJnYXVzc2lhbiIsCiAgICBkYXRhID0gcmFuZG9tX3NwYW5fbW9kZWwsCiAgICBuLnRyZWVzID0gNjAwMCwKICAgIGludGVyYWN0aW9uLmRlcHRoID0gaHlwZXJfZ3JpZCRpbnRlcmFjdGlvbi5kZXB0aFtpXSwKICAgIHNocmlua2FnZSA9IGh5cGVyX2dyaWQkc2hyaW5rYWdlW2ldLAogICAgbi5taW5vYnNpbm5vZGUgPSBoeXBlcl9ncmlkJG4ubWlub2JzaW5ub2RlW2ldLAogICAgYmFnLmZyYWN0aW9uID0gaHlwZXJfZ3JpZCRiYWcuZnJhY3Rpb25baV0sCiAgICB0cmFpbi5mcmFjdGlvbiA9IC43NSwKICAgIG4uY29yZXMgPSBOVUxMLCAjIHdpbGwgdXNlIGFsbCBjb3JlcyBieSBkZWZhdWx0CiAgICB2ZXJib3NlID0gRkFMU0UKICApCiAgCiAgIyBhZGQgbWluIHRyYWluaW5nIGVycm9yIGFuZCB0cmVlcyB0byBncmlkCiAgaHlwZXJfZ3JpZCRvcHRpbWFsX3RyZWVzW2ldIDwtIHdoaWNoLm1pbihnYm0udHVuZSR2YWxpZC5lcnJvcikKICBoeXBlcl9ncmlkJG1pbl9STVNFW2ldIDwtIHNxcnQobWluKGdibS50dW5lJHZhbGlkLmVycm9yKSkKfQoKCiMgc2F2ZShoeXBlcl9ncmlkLCBmaWxlID0gIi4vZGF0YS9oeXBlcl9ncmlkLlJkYSIpCgpoeXBlcl9ncmlkICU+JSAKICBhcnJhbmdlKG1pbl9STVNFKSAlPiUgCiAgZGF0YXRhYmxlKCkKCgpgYGAKClNvIGFmdGVyIHNlbGVjdGluZyB0aGUgYmVzdCBtb2RlbCAobG93ZXN0IFJNU0UgLSDigqwgNDI3LDQzNCkgaSBkZXZlbG9wZWQgdGhlIGZpbmFsIG1vZGVsIAp1c2luZyB0aGUgc3BlY2lmaWVkIGh5cGVycGFyYW1ldGVycyAmIHVzaW5nIDEwLWZvbGQgY3Jvc3MgdmFsaWRhdGlvbi4gClRoZW4gd2UgcHJpbnQgYSBmZWF0dXJlIGltcG9ydGFuY2UgcGxvdC4gVGhlIG1vc3QgaW1wb3J0YW50IGZlYXR1cmUgc2VlbXMgdG8gYmUgCnRoZSAqKnNpemUgb2YgdGhlIHByb3BlcnR5KiogKHNxdWFyZSBtZXRlcnMpLiBUaGUgKipjb25zdHJ1Y3Rpb24geWVhcioqIAomICoqbnVtYmVyIG9mIHJvb21zKiogYXJlIHZlcnkgaW1wb3J0YW50LiBUaGVuICoqZ2VvZ3JhcGh5X25hbWUqKiwgKipyYW5raW5nX3Njb3JlKiosCioqc3VidHlwZSoqICYgKipudW1iZXIgb2YgYmF0aHJvb21zKiogYXJlIHNvbWV3aGF0IGltb3J0YW50IGJ1dCB0aGUgcmVzdCBzZWVtcyB0byAKYmUgdW5pbXBvcnRhbnQuCiAgCgpgYGB7cn0KCnNldC5zZWVkKDEyMykKCiMgdHJhaW4gR0JNIG1vZGVsCmdibS5maW5hbCA8LSBnYm0oCiAgZm9ybXVsYSA9IHByaWNlIH4gLiwKICBkaXN0cmlidXRpb24gPSAiZ2F1c3NpYW4iLAogIGRhdGEgPSByYW5kb21fc3Bhbl9tb2RlbCwKICBuLnRyZWVzID0gNTczMiwKICBpbnRlcmFjdGlvbi5kZXB0aCA9IDMsCiAgc2hyaW5rYWdlID0gMC4xLAogIG4ubWlub2JzaW5ub2RlID0gNywKICBiYWcuZnJhY3Rpb24gPSAuOCwgCiAgdHJhaW4uZnJhY3Rpb24gPSAxLAogIGN2LmZvbGRzID0gMTAsCiAgbi5jb3JlcyA9IE5VTEwsIAogIHZlcmJvc2UgPSBGQUxTRQogICkgIAoKCnZpcDo6dmlwKGdibS5maW5hbCkgKwogIGxhYnModGl0bGUgPSAiRmVhdHVyZSBpbXBvcnRhbmNlIHBsb3QiLAogICAgICAgc3VidGl0bGUgPSAiSGlnaGVyIGltcG9ydGFuY2UgbWVhbnMgbW9yZSBpbXBvcnRhbnQgaW4gcHJlZGljdGlvbiBtb2RlbCIpCgoKYGBgCgpOb3cgbGV0J3Mgc2F5IHdlIHdhbnQgdG8gcHJlZGljdCB0aGUgdmFsdWUgb2YgYSBuZXcgcHJvcGVydHkuIEFmdGVyIGNyZWF0aW5nIHRoZSBkYXRhc2V0CmJ5IGluc2VydGluZyB0aGUgdmFyaWFibGVzIG9mIHRoZSBwcm9wZXJ0eSwgd2UgcnVuIHRoZSBwcmVkaWN0aW9uIGFuZCBpdCByZXR1cm5zIAphIHByZWRpY3RlZCB2YWx1ZSBvZiDigqwgMjIzLDA3My45IAoKCmBgYHtyfQoKCm5ld19kYXRhIDwtIApzdHJ1Y3R1cmUobGlzdCgKICAgIHJhbmtpbmdfc2NvcmUgPSAxMjIsIAogICAgZ2VvZ3JhcGh5X25hbWUgPSBzdHJ1Y3R1cmUoM0wsIC5MYWJlbCA9IGMoImJlZXN5IG5laWdoYm9yaG9vZCIsICJnZW50cmlmaWNhdGlvbiBhcmVhIiwgIm5vcnRoZXJuIHN1YiIsICJzb3V0aCBiZWFjaCIpLCBjbGFzcyA9ICJmYWN0b3IiKSwgCiAgICBzcV9tZXRlcnMgPSA5NSwgCiAgICBwcmljZSA9IDIzMDAwMCwgCiAgICB5ZWFyX29mX2NvbnN0cnVjdGlvbiA9IDIwMDcsIAogICAgc3VidHlwZSA9IHN0cnVjdHVyZSgxTCwgLkxhYmVsID0gYygiYXBhcnRtZW50IiwgImFwYXJ0bWVudCBjb21wbGV4IiwgImJ1aWxkaW5nIiwgImJ1bmdhbG93IiwgImRldGFjaGVkIiwgImhvdXNlYm9hdCIsICJsb2Z0IiwgIm1haXNvbmV0dGUiLCAib3RoZXIgcmVzaWRlbnRpYWwiLCAic3R1ZGlvIiwgInZpbGxhIiksIGNsYXNzID0gImZhY3RvciIpLCAKICAgIHJvb21zID0gMywgCiAgICBub19vZl9iYXRocm9vbXMgPSAxLCAKICAgIG5vX29mX3djID0gMSwgCiAgICBhZF90eXBlID0gc3RydWN0dXJlKDJMLCAuTGFiZWwgPSBjKCJwcmVtaXVtIiwgInNpbXBsZSIsICJzdGFyIiwgInVwIiksIGNsYXNzID0gImZhY3RvciIpLCAKICAgIGxpdmluZ19yb29tcyA9IDAsIAogICAga2l0Y2hlbnMgPSAxLCAKICAgIGJhbGNvbnlfYXJlYSA9IDApLCAKICAgIGNsYXNzID0gImRhdGEuZnJhbWUiLCByb3cubmFtZXMgPSBjKE5BLCAtMUwpKQoKCgojIHByZWRpY3QgdmFsdWVzIGZvciB0ZXN0IGRhdGEKcHJlZF9uZXcgPC0gcHJlZGljdChnYm0uZmluYWwsIG4udHJlZXMgPSBnYm0uZmluYWwkbi50cmVlcywgbmV3X2RhdGEpCgpwcmVkX25ldwoKYGBgCgoKSW4gdGhpcyBjYXNlIGkgdXNlZCB0aGUgc2FtZSBtb2RlbCBmb3IgcHJlZGljdGlvbiAmIGluZmVyZW5jZS4gzplmIHRoZXJlIGlzIG1vcmUKdGltZSwgZGlmZmVyZW50IGFsZ29yaXRobXMgY291bGQgYmUgYXBwbGllZCBhbmQgZGV2ZWxvcCBkaWZmZXJlbnQgbW9kZWxzIGUuZyBMaW5lYXIKbW9kZWxzIGZvciBpbmZlcmVuY2UuCgpPZiBjb3Vyc2Ugd2UgbmVlZCBmdXJ0aGVyIHdvcmsgdG8gZGV2ZWxvcCBhIHJlbGlhYmxlIG1vZGVsIHRoYXQgcHJlZGljdHMKdGhlIGhvdXNlIHByaWNlIHdpdGggYmV0dGVyIGFjY3VyYWN5LiBJIHdvdWxkIHRha2UgdGhlIGZvbGxvd2luZyBhY3Rpb25zIHRvIAppbXByb3ZlIHRoZSBtb2RlbDogIAoKLSBQcmVwYXJlIGEgYmV0dGVyIHN0cmF0ZWd5IGZvciAqKmZlYXR1cmUgc2VsZWN0aW9uKiouIEkgd291bGQgdHJ5IHZhcmlvdXMgbWV0aG9kcwpmcm9tIGludHJpbnNpYyhlLmcuIG1vcmUgbW9kZWxzKSwgZmlsdGVyKGUuZy4gY2hlY2sgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlKSAmIAp3cmFwcGVyIGNsYXNzZXMgKGUuZy4gYmFja3dvcmRzL2ZvcndhcmQgZWxpbWluYXRpb24pIG9mIGZlYXR1cmUgc2VsZWN0aW9uLgotIFdvcmsgYSBsb3QgaW4gKipmZWF0dXJlIGVuZ2luZWVyaW5nKiouIEUuZyBzdW1tYXJpemUgY2F0ZWdvcmllcywgZW5jb2RlIHRvIG5vbWluYWwgCmluIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gQWxzbyB0cnkgdHJhbnNmb3JtYXRpb25zIChzY2FsaW5nLCBzbW9vdGhpbmcsIGJpbm5pbmcgZXRjLikgCmluIG51bWVyaWNhbCBwcmVkaWN0b3JzICYgdHJ5IHNvbWUgMi13YXkgb3IgZXZlbiAzLXdheSBpbnRlcmFjdGlvbnMuICAKLSBUcnkgKiptb3JlIG1vZGVscyoqIHdpdGggZnVydGhlciBoeXBlcnBhcmFtZXRlcnMgdHVuaW5nLiBlLmcuIFJhbmRvbSBGb3Jlc3QsIERlZXAgCm5ldXJhbCBuZXR3b3JrcyAKLSBDcmVhdGUgYSBzaGlueSBhcHBsaWNhdGlvbiAoaW50ZXJhY3RpdmUgd2ViIGRhc2hib2FyZHMpIGluIG9yZGVyIHRvIHByZXNlbnQgdGhlIHJlc3VsdHMgdG8gdGhlIHN0YWtlaG9sZGVycy4gClRoaXMgaXMgYSBzYW1wbGUgb2YgYSBbZm9yZWNhc3RpbmcgYXBwbGljYXRpb25dKGh0dHBzOi8vbWFudG9uaW91LnNoaW55YXBwcy5pby9Gb3JlY2FzdGluZy8pIGFuZCBhIFtjbHVzdGVyaW5nIGFwcGxpY2F0aW9uXShodHRwczovL21hbnRvbmlvdS5zaGlueWFwcHMuaW8vQ2x1c3RlcmluZy8pIGkgaGF2ZSBjcmVhdGVkIGluIHRoZSBwYXN0LgoKCgojIEFzc2lnbm1lbnQgUGFydCAyCgpBIHZlcnkgaW1wb3J0YW50IG1ldHJpYyB0byBzaG93IHRoZSBjb21wZXRpdGl2ZW5lc3MgaXMgdGhlIHByaWNlLiBUaGUgZm9sbG93aW5nCnRhYmxlIGxpc3RzIHNvbWUgYmFzaWMgcHJpY2UgbWVhc3VyZXMgcGVyIGFyZWEKCmBgYHtyfQoKc3BhbiAlPiUgCiAgZ3JvdXBfYnkoZ2VvZ3JhcGh5X25hbWUpICU+JSAKICBzdW1tYXJpc2UoTiA9IG4oKSwKICAgICAgICAgICAgbWVhbl9wcmljZSA9IHJvdW5kKG1lYW4ocHJpY2UpLCAwKSwgCiAgICAgICAgICAgIHNkX3ByaWNlID0gcm91bmQoc2QocHJpY2UpLCAwKSwKICAgICAgICAgICAgbWluX3ByaWNlID0gbWluKHByaWNlKSwKICAgICAgICAgICAgcXVhbnRpbGVfMjUgPSBxdWFudGlsZShwcmljZSwgcHJvYnMgPSAuMjUpLAogICAgICAgICAgICBtZWRpYW4gPSBtZWRpYW4ocHJpY2UpLAogICAgICAgICAgICBxdWFudGlsZSA9IHF1YW50aWxlKHByaWNlLCBwcm9icyA9IC43NSksCiAgICAgICAgICAgIG1heF9wcmljZSA9IG1heChwcmljZSkKICAgICAgICAgICAgKSAlPiUKICBkYXRhdGFibGUoKQoKCgoKYGBgCgoKYGBge3IgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTB9CmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KHNjYWxlcykKCgpnZ3Bsb3RseSgKICAgICAgICAgZ2dwbG90KHNwYW4sIGFlcyhwcmljZSwgZmlsbCA9IGdlb2dyYXBoeV9uYW1lKSkgKwogICAgICAgICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjUpICsKICAgICAgICAgc2NhbGVfeF9sb2cxMChsYWJlbHMgPSBkb2xsYXJfZm9ybWF0KHN1ZmZpeCA9ICLigqwiLCBwcmVmaXggPSAiIikpICsKICAgICAgICAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkgKwogICAgICAgICBzY2FsZV9maWxsX3RhYmxlYXUoKSArCiAgICAgICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgICAgICBsYWJzKHRpdGxlID0gIlByb3BlcnR5IHByaWNlcyBkaXN0cmlidXRpb24gcGVyIGFyZWEiKQogICAgICAgICAgKQoKYGBgCgpTb21lIG5leHQgc3RlcHMgd291bGQgYmUgdG8gZGlzY292ZXIgb3RoZXIgbWVhc3VyZXMgYW5kIGNoZWNrIGhvdyBkaWZmZXJlbnQgdGhlc2UKYXJlIHBlciBhcmVhLiBBdCB0aGUgZW5kIGl0IHdpbGwgYmUgYSBnb29kIGlkZWEgdG8gZGV2ZWxvcCBhIHNpbmdsZSBLUEkgdG8gbWVhc3VyZSB0aGUKY29tcGV0aXRpdmVuZXNzIG9mIGVhY2ggYXJlYS4gVGhpcyBLUEkgd291bGQgY29tYmluZSBhbGwgc2lnbmlmaWNhbnQgbWVhc3VyZXMgCndlIGhhdmUgZGlzY292ZXJlZC4gClRoaXMgd291bGQgZGVmaW5pdGVseSBuZWVkIGNsb3NlIGNvb3BlcmF0aW9uIHdpdGggYnVzaW5lc3Mgc3Rha2Vob2xkZXJzIGFuZApob3VzZSBtYXJrZXQgZXhwZXJ0cy4KCg==